home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Modules / cdmodule.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-03  |  19.0 KB  |  859 lines

  1. /* CD module -- interface to Mark Callow's and Roger Chickering's */
  2.  /* CD Audio Library (CD). */
  3.  
  4. #include <sys/types.h>
  5. #include <cdaudio.h>
  6. #include "Python.h"
  7.  
  8. #define NCALLBACKS    8
  9.  
  10. typedef struct {
  11.     PyObject_HEAD
  12.     CDPLAYER *ob_cdplayer;
  13. } cdplayerobject;
  14.  
  15. static PyObject *CdError;        /* exception cd.error */
  16.  
  17. static PyObject *
  18. CD_allowremoval(self, args)
  19.     cdplayerobject *self;
  20.     PyObject *args;
  21. {
  22.     if (!PyArg_ParseTuple(args, ":allowremoval"))
  23.         return NULL;
  24.  
  25.     CDallowremoval(self->ob_cdplayer);
  26.  
  27.     Py_INCREF(Py_None);
  28.     return Py_None;
  29. }
  30.  
  31. static PyObject *
  32. CD_preventremoval(self, args)
  33.     cdplayerobject *self;
  34.     PyObject *args;
  35. {
  36.     if (!PyArg_ParseTuple(args, ":preventremoval"))
  37.         return NULL;
  38.  
  39.     CDpreventremoval(self->ob_cdplayer);
  40.  
  41.     Py_INCREF(Py_None);
  42.     return Py_None;
  43. }
  44.  
  45. static PyObject *
  46. CD_bestreadsize(self, args)
  47.     cdplayerobject *self;
  48.     PyObject *args;
  49. {
  50.     if (!PyArg_ParseTuple(args, ":bestreadsize"))
  51.         return NULL;
  52.  
  53.     return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer));
  54. }
  55.  
  56. static PyObject *
  57. CD_close(self, args)
  58.     cdplayerobject *self;
  59.     PyObject *args;
  60. {
  61.     if (!PyArg_ParseTuple(args, ":close"))
  62.         return NULL;
  63.  
  64.     if (!CDclose(self->ob_cdplayer)) {
  65.         PyErr_SetFromErrno(CdError); /* XXX - ??? */
  66.         return NULL;
  67.     }
  68.     self->ob_cdplayer = NULL;
  69.  
  70.     Py_INCREF(Py_None);
  71.     return Py_None;
  72. }
  73.  
  74. static PyObject *
  75. CD_eject(self, args)
  76.     cdplayerobject *self;
  77.     PyObject *args;
  78. {
  79.     CDSTATUS status;
  80.  
  81.     if (!PyArg_ParseTuple(args, ":eject"))
  82.         return NULL;
  83.  
  84.     if (!CDeject(self->ob_cdplayer)) {
  85.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  86.             status.state == CD_NODISC)
  87.             PyErr_SetString(CdError, "no disc in player");
  88.         else
  89.             PyErr_SetString(CdError, "eject failed");
  90.         return NULL;
  91.     }
  92.  
  93.     Py_INCREF(Py_None);
  94.     return Py_None;
  95. }
  96.     
  97. static PyObject *
  98. CD_getstatus(self, args)
  99.     cdplayerobject *self;
  100.     PyObject *args;
  101. {
  102.     CDSTATUS status;
  103.  
  104.     if (!PyArg_ParseTuple(args, ":getstatus"))
  105.         return NULL;
  106.  
  107.     if (!CDgetstatus(self->ob_cdplayer, &status)) {
  108.         PyErr_SetFromErrno(CdError); /* XXX - ??? */
  109.         return NULL;
  110.     }
  111.  
  112.     return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state,
  113.                status.track, status.min, status.sec, status.frame,
  114.                status.abs_min, status.abs_sec, status.abs_frame,
  115.                status.total_min, status.total_sec, status.total_frame,
  116.                status.first, status.last, status.scsi_audio,
  117.                status.cur_block);
  118. }
  119.     
  120. static PyObject *
  121. CD_gettrackinfo(self, args)
  122.     cdplayerobject *self;
  123.     PyObject *args;
  124. {
  125.     int track;
  126.     CDTRACKINFO info;
  127.     CDSTATUS status;
  128.  
  129.     if (!PyArg_ParseTuple(args, "i:gettrackinfo", &track))
  130.         return NULL;
  131.  
  132.     if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
  133.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  134.             status.state == CD_NODISC)
  135.             PyErr_SetString(CdError, "no disc in player");
  136.         else
  137.             PyErr_SetString(CdError, "gettrackinfo failed");
  138.         return NULL;
  139.     }
  140.  
  141.     return Py_BuildValue("((iii)(iii))",
  142.                info.start_min, info.start_sec, info.start_frame,
  143.                info.total_min, info.total_sec, info.total_frame);
  144. }
  145.     
  146. static PyObject *
  147. CD_msftoblock(self, args)
  148.     cdplayerobject *self;
  149.     PyObject *args;
  150. {
  151.     int min, sec, frame;
  152.  
  153.     if (!PyArg_ParseTuple(args, "iii:msftoblock", &min, &sec, &frame))
  154.         return NULL;
  155.  
  156.     return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer,
  157.                         min, sec, frame));
  158. }
  159.     
  160. static PyObject *
  161. CD_play(self, args)
  162.     cdplayerobject *self;
  163.     PyObject *args;
  164. {
  165.     int start, play;
  166.     CDSTATUS status;
  167.  
  168.     if (!PyArg_ParseTuple(args, "ii:play", &start, &play))
  169.         return NULL;
  170.  
  171.     if (!CDplay(self->ob_cdplayer, start, play)) {
  172.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  173.             status.state == CD_NODISC)
  174.             PyErr_SetString(CdError, "no disc in player");
  175.         else
  176.             PyErr_SetString(CdError, "play failed");
  177.         return NULL;
  178.     }
  179.  
  180.     Py_INCREF(Py_None);
  181.     return Py_None;
  182. }
  183.     
  184. static PyObject *
  185. CD_playabs(self, args)
  186.     cdplayerobject *self;
  187.     PyObject *args;
  188. {
  189.     int min, sec, frame, play;
  190.     CDSTATUS status;
  191.  
  192.     if (!PyArg_ParseTuple(args, "iiii:playabs", &min, &sec, &frame, &play))
  193.         return NULL;
  194.  
  195.     if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
  196.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  197.             status.state == CD_NODISC)
  198.             PyErr_SetString(CdError, "no disc in player");
  199.         else
  200.             PyErr_SetString(CdError, "playabs failed");
  201.         return NULL;
  202.     }
  203.  
  204.     Py_INCREF(Py_None);
  205.     return Py_None;
  206. }
  207.     
  208. static PyObject *
  209. CD_playtrack(self, args)
  210.     cdplayerobject *self;
  211.     PyObject *args;
  212. {
  213.     int start, play;
  214.     CDSTATUS status;
  215.  
  216.     if (!PyArg_ParseTuple(args, "ii:playtrack", &start, &play))
  217.         return NULL;
  218.  
  219.     if (!CDplaytrack(self->ob_cdplayer, start, play)) {
  220.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  221.             status.state == CD_NODISC)
  222.             PyErr_SetString(CdError, "no disc in player");
  223.         else
  224.             PyErr_SetString(CdError, "playtrack failed");
  225.         return NULL;
  226.     }
  227.  
  228.     Py_INCREF(Py_None);
  229.     return Py_None;
  230. }
  231.     
  232. static PyObject *
  233. CD_playtrackabs(self, args)
  234.     cdplayerobject *self;
  235.     PyObject *args;
  236. {
  237.     int track, min, sec, frame, play;
  238.     CDSTATUS status;
  239.  
  240.     if (!PyArg_ParseTuple(args, "iiiii:playtrackabs", &track, &min, &sec,
  241.                   &frame, &play))
  242.         return NULL;
  243.  
  244.     if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
  245.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  246.             status.state == CD_NODISC)
  247.             PyErr_SetString(CdError, "no disc in player");
  248.         else
  249.             PyErr_SetString(CdError, "playtrackabs failed");
  250.         return NULL;
  251.     }
  252.  
  253.     Py_INCREF(Py_None);
  254.     return Py_None;
  255. }
  256.     
  257. static PyObject *
  258. CD_readda(self, args)
  259.     cdplayerobject *self;
  260.     PyObject *args;
  261. {
  262.     int numframes, n;
  263.     PyObject *result;
  264.  
  265.     if (!PyArg_ParseTuple(args, "i:readda", &numframes))
  266.         return NULL;
  267.  
  268.     result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME));
  269.     if (result == NULL)
  270.         return NULL;
  271.  
  272.     n = CDreadda(self->ob_cdplayer,
  273.                (CDFRAME *) PyString_AsString(result), numframes);
  274.     if (n == -1) {
  275.         Py_DECREF(result);
  276.         PyErr_SetFromErrno(CdError);
  277.         return NULL;
  278.     }
  279.     if (n < numframes)
  280.         if (_PyString_Resize(&result, n * sizeof(CDFRAME)))
  281.             return NULL;
  282.  
  283.     return result;
  284. }
  285.  
  286. static PyObject *
  287. CD_seek(self, args)
  288.     cdplayerobject *self;
  289.     PyObject *args;
  290. {
  291.     int min, sec, frame;
  292.     long PyTryBlock;
  293.  
  294.     if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame))
  295.         return NULL;
  296.  
  297.     PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame);
  298.     if (PyTryBlock == -1) {
  299.         PyErr_SetFromErrno(CdError);
  300.         return NULL;
  301.     }
  302.  
  303.     return PyInt_FromLong(PyTryBlock);
  304. }
  305.     
  306. static PyObject *
  307. CD_seektrack(self, args)
  308.     cdplayerobject *self;
  309.     PyObject *args;
  310. {
  311.     int track;
  312.     long PyTryBlock;
  313.  
  314.     if (!PyArg_ParseTuple(args, "i:seektrack", &track))
  315.         return NULL;
  316.  
  317.     PyTryBlock = CDseektrack(self->ob_cdplayer, track);
  318.     if (PyTryBlock == -1) {
  319.         PyErr_SetFromErrno(CdError);
  320.         return NULL;
  321.     }
  322.  
  323.     return PyInt_FromLong(PyTryBlock);
  324. }
  325.     
  326. static PyObject *
  327. CD_seekblock(self, args)
  328.     cdplayerobject *self;
  329.     PyObject *args;
  330. {
  331.     unsigned long PyTryBlock;
  332.  
  333.     if (!PyArg_ParseTuple(args, "l:seekblock", &PyTryBlock))
  334.         return NULL;
  335.  
  336.     PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock);
  337.     if (PyTryBlock == (unsigned long) -1) {
  338.         PyErr_SetFromErrno(CdError);
  339.         return NULL;
  340.     }
  341.  
  342.     return PyInt_FromLong(PyTryBlock);
  343. }
  344.     
  345. static PyObject *
  346. CD_stop(self, args)
  347.     cdplayerobject *self;
  348.     PyObject *args;
  349. {
  350.     CDSTATUS status;
  351.  
  352.     if (!PyArg_ParseTuple(args, ":stop"))
  353.         return NULL;
  354.  
  355.     if (!CDstop(self->ob_cdplayer)) {
  356.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  357.             status.state == CD_NODISC)
  358.             PyErr_SetString(CdError, "no disc in player");
  359.         else
  360.             PyErr_SetString(CdError, "stop failed");
  361.         return NULL;
  362.     }
  363.  
  364.     Py_INCREF(Py_None);
  365.     return Py_None;
  366. }
  367.     
  368. static PyObject *
  369. CD_togglepause(self, args)
  370.     cdplayerobject *self;
  371.     PyObject *args;
  372. {
  373.     CDSTATUS status;
  374.  
  375.     if (!PyArg_ParseTuple(args, ":togglepause"))
  376.         return NULL;
  377.  
  378.     if (!CDtogglepause(self->ob_cdplayer)) {
  379.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  380.             status.state == CD_NODISC)
  381.             PyErr_SetString(CdError, "no disc in player");
  382.         else
  383.             PyErr_SetString(CdError, "togglepause failed");
  384.         return NULL;
  385.     }
  386.  
  387.     Py_INCREF(Py_None);
  388.     return Py_None;
  389. }
  390.     
  391. static PyMethodDef cdplayer_methods[] = {
  392.     {"allowremoval",    (PyCFunction)CD_allowremoval,    1},
  393.     {"bestreadsize",    (PyCFunction)CD_bestreadsize,    1},
  394.     {"close",        (PyCFunction)CD_close,        1},
  395.     {"eject",        (PyCFunction)CD_eject,        1},
  396.     {"getstatus",        (PyCFunction)CD_getstatus,        1},
  397.     {"gettrackinfo",    (PyCFunction)CD_gettrackinfo,    1},
  398.     {"msftoblock",        (PyCFunction)CD_msftoblock,        1},
  399.     {"play",        (PyCFunction)CD_play,        1},
  400.     {"playabs",        (PyCFunction)CD_playabs,        1},
  401.     {"playtrack",        (PyCFunction)CD_playtrack,        1},
  402.     {"playtrackabs",    (PyCFunction)CD_playtrackabs,    1},
  403.     {"preventremoval",    (PyCFunction)CD_preventremoval,    1},
  404.     {"readda",        (PyCFunction)CD_readda,        1},
  405.     {"seek",        (PyCFunction)CD_seek,        1},
  406.     {"seekblock",        (PyCFunction)CD_seekblock,        1},
  407.     {"seektrack",        (PyCFunction)CD_seektrack,        1},
  408.     {"stop",        (PyCFunction)CD_stop,        1},
  409.     {"togglepause",        (PyCFunction)CD_togglepause,       1},
  410.     {NULL,            NULL}         /* sentinel */
  411. };
  412.  
  413. static void
  414. cdplayer_dealloc(self)
  415.     cdplayerobject *self;
  416. {
  417.     if (self->ob_cdplayer != NULL)
  418.         CDclose(self->ob_cdplayer);
  419.     PyObject_Del(self);
  420. }
  421.  
  422. static PyObject *
  423. cdplayer_getattr(self, name)
  424.     cdplayerobject *self;
  425.     char *name;
  426. {
  427.     if (self->ob_cdplayer == NULL) {
  428.         PyErr_SetString(PyExc_RuntimeError, "no player active");
  429.         return NULL;
  430.     }
  431.     return Py_FindMethod(cdplayer_methods, (PyObject *)self, name);
  432. }
  433.  
  434. PyTypeObject CdPlayertype = {
  435.     PyObject_HEAD_INIT(&PyType_Type)
  436.     0,            /*ob_size*/
  437.     "cdplayer",        /*tp_name*/
  438.     sizeof(cdplayerobject),    /*tp_size*/
  439.     0,            /*tp_itemsize*/
  440.     /* methods */
  441.     (destructor)cdplayer_dealloc, /*tp_dealloc*/
  442.     0,            /*tp_print*/
  443.     (getattrfunc)cdplayer_getattr, /*tp_getattr*/
  444.     0,            /*tp_setattr*/
  445.     0,            /*tp_compare*/
  446.     0,            /*tp_repr*/
  447. };
  448.  
  449. static PyObject *
  450. newcdplayerobject(cdp)
  451.     CDPLAYER *cdp;
  452. {
  453.     cdplayerobject *p;
  454.  
  455.     p = PyObject_New(cdplayerobject, &CdPlayertype);
  456.     if (p == NULL)
  457.         return NULL;
  458.     p->ob_cdplayer = cdp;
  459.     return (PyObject *) p;
  460. }
  461.  
  462. static PyObject *
  463. CD_open(self, args)
  464.     PyObject *self, *args;
  465. {
  466.     char *dev, *direction;
  467.     CDPLAYER *cdp;
  468.  
  469.     /*
  470.      * Variable number of args.
  471.      * First defaults to "None", second defaults to "r".
  472.      */
  473.     dev = NULL;
  474.     direction = "r";
  475.     if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction))
  476.         return NULL;
  477.  
  478.     cdp = CDopen(dev, direction);
  479.     if (cdp == NULL) {
  480.         PyErr_SetFromErrno(CdError);
  481.         return NULL;
  482.     }
  483.  
  484.     return newcdplayerobject(cdp);
  485. }
  486.  
  487. typedef struct {
  488.     PyObject_HEAD
  489.     CDPARSER *ob_cdparser;
  490.     struct {
  491.         PyObject *ob_cdcallback;
  492.         PyObject *ob_cdcallbackarg;
  493.     } ob_cdcallbacks[NCALLBACKS];
  494. } cdparserobject;
  495.  
  496. static void
  497. CD_callback(arg, type, data)
  498.     void *arg;
  499.     CDDATATYPES type;
  500.     void *data;
  501. {
  502.     PyObject *result, *args, *v = NULL;
  503.     char *p;
  504.     int i;
  505.     cdparserobject *self;
  506.  
  507.     self = (cdparserobject *) arg;
  508.     args = PyTuple_New(3);
  509.     if (args == NULL)
  510.         return;
  511.     Py_INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
  512.     PyTuple_SetItem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg);
  513.     PyTuple_SetItem(args, 1, PyInt_FromLong((long) type));
  514.     switch (type) {
  515.     case cd_audio:
  516.         v = PyString_FromStringAndSize(data, CDDA_DATASIZE);
  517.         break;
  518.     case cd_pnum:
  519.     case cd_index:
  520.         v = PyInt_FromLong(((CDPROGNUM *) data)->value);
  521.         break;
  522.     case cd_ptime:
  523.     case cd_atime:
  524. #define ptr ((struct cdtimecode *) data)
  525.         v = Py_BuildValue("(iii)",
  526.                 ptr->mhi * 10 + ptr->mlo,
  527.                 ptr->shi * 10 + ptr->slo,
  528.                 ptr->fhi * 10 + ptr->flo);
  529. #undef ptr
  530.         break;
  531.     case cd_catalog:
  532.         v = PyString_FromStringAndSize(NULL, 13);
  533.         p = PyString_AsString(v);
  534.         for (i = 0; i < 13; i++)
  535.             *p++ = ((char *) data)[i] + '0';
  536.         break;
  537.     case cd_ident:
  538. #define ptr ((struct cdident *) data)
  539.         v = PyString_FromStringAndSize(NULL, 12);
  540.         p = PyString_AsString(v);
  541.         CDsbtoa(p, ptr->country, 2);
  542.         p += 2;
  543.         CDsbtoa(p, ptr->owner, 3);
  544.         p += 3;
  545.         *p++ = ptr->year[0] + '0';
  546.         *p++ = ptr->year[1] + '0';
  547.         *p++ = ptr->serial[0] + '0';
  548.         *p++ = ptr->serial[1] + '0';
  549.         *p++ = ptr->serial[2] + '0';
  550.         *p++ = ptr->serial[3] + '0';
  551.         *p++ = ptr->serial[4] + '0';
  552. #undef ptr
  553.         break;
  554.     case cd_control:
  555.         v = PyInt_FromLong((long) *((unchar *) data));
  556.         break;
  557.     }
  558.     PyTuple_SetItem(args, 2, v);
  559.     if (PyErr_Occurred()) {
  560.         Py_DECREF(args);
  561.         return;
  562.     }
  563.     
  564.     result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback,
  565.                    args);
  566.     Py_DECREF(args);
  567.     Py_XDECREF(result);
  568. }
  569.  
  570. static PyObject *
  571. CD_deleteparser(self, args)
  572.     cdparserobject *self;
  573.     PyObject *args;
  574. {
  575.     int i;
  576.  
  577.     if (!PyArg_ParseTuple(args, ":deleteparser"))
  578.         return NULL;
  579.  
  580.     CDdeleteparser(self->ob_cdparser);
  581.     self->ob_cdparser = NULL;
  582.  
  583.     /* no sense in keeping the callbacks, so remove them */
  584.     for (i = 0; i < NCALLBACKS; i++) {
  585.         Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
  586.         self->ob_cdcallbacks[i].ob_cdcallback = NULL;
  587.         Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
  588.         self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
  589.     }
  590.  
  591.     Py_INCREF(Py_None);
  592.     return Py_None;
  593. }
  594.  
  595. static PyObject *
  596. CD_parseframe(self, args)
  597.     cdparserobject *self;
  598.     PyObject *args;
  599. {
  600.     char *cdfp;
  601.     int length;
  602.     CDFRAME *p;
  603.  
  604.     if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length))
  605.         return NULL;
  606.  
  607.     if (length % sizeof(CDFRAME) != 0) {
  608.         PyErr_SetString(PyExc_TypeError, "bad length");
  609.         return NULL;
  610.     }
  611.  
  612.     p = (CDFRAME *) cdfp;
  613.     while (length > 0) {
  614.         CDparseframe(self->ob_cdparser, p);
  615.         length -= sizeof(CDFRAME);
  616.         p++;
  617.         if (PyErr_Occurred())
  618.             return NULL;
  619.     }
  620.  
  621.     Py_INCREF(Py_None);
  622.     return Py_None;
  623. }
  624.  
  625. static PyObject *
  626. CD_removecallback(self, args)
  627.     cdparserobject *self;
  628.     PyObject *args;
  629. {
  630.     int type;
  631.  
  632.     if (!PyArg_ParseTuple(args, "i:removecallback", &type))
  633.         return NULL;
  634.  
  635.     if (type < 0 || type >= NCALLBACKS) {
  636.         PyErr_SetString(PyExc_TypeError, "bad type");
  637.         return NULL;
  638.     }
  639.  
  640.     CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);
  641.  
  642.     Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
  643.     self->ob_cdcallbacks[type].ob_cdcallback = NULL;
  644.  
  645.     Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
  646.     self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL;
  647.  
  648.     Py_INCREF(Py_None);
  649.     return Py_None;
  650. }
  651.  
  652. static PyObject *
  653. CD_resetparser(self, args)
  654.     cdparserobject *self;
  655.     PyObject *args;
  656. {
  657.     if (!PyArg_ParseTuple(args, ":resetparser"))
  658.         return NULL;
  659.  
  660.     CDresetparser(self->ob_cdparser);
  661.  
  662.     Py_INCREF(Py_None);
  663.     return Py_None;
  664. }
  665.  
  666. static PyObject *
  667. CD_addcallback(self, args)
  668.     cdparserobject *self;
  669.     PyObject *args;
  670. {
  671.     int type;
  672.     PyObject *func, *funcarg;
  673.  
  674.     /* XXX - more work here */
  675.     if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg))
  676.         return NULL;
  677.  
  678.     if (type < 0 || type >= NCALLBACKS) {
  679.         PyErr_SetString(PyExc_TypeError, "argument out of range");
  680.         return NULL;
  681.     }
  682.  
  683. #ifdef CDsetcallback
  684.     CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
  685.               (void *) self);
  686. #else
  687.     CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
  688.               (void *) self);
  689. #endif
  690.     Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
  691.     Py_INCREF(func);
  692.     self->ob_cdcallbacks[type].ob_cdcallback = func;
  693.     Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
  694.     Py_INCREF(funcarg);
  695.     self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg;
  696.  
  697. /*
  698.     if (type == cd_audio) {
  699.         sigfpe_[_UNDERFL].repls = _ZERO;
  700.         handle_sigfpes(_ON, _EN_UNDERFL, NULL,
  701.                                 _ABORT_ON_ERROR, NULL);
  702.     }
  703. */
  704.  
  705.     Py_INCREF(Py_None);
  706.     return Py_None;
  707. }
  708.  
  709. static PyMethodDef cdparser_methods[] = {
  710.     {"addcallback",        (PyCFunction)CD_addcallback,       1},
  711.     {"deleteparser",    (PyCFunction)CD_deleteparser,    1},
  712.     {"parseframe",        (PyCFunction)CD_parseframe,    1},
  713.     {"removecallback",    (PyCFunction)CD_removecallback,    1},
  714.     {"resetparser",        (PyCFunction)CD_resetparser,    1},
  715.                                         /* backward compatibility */
  716.     {"setcallback",        (PyCFunction)CD_addcallback,       1},
  717.     {NULL,            NULL}         /* sentinel */
  718. };
  719.  
  720. static void
  721. cdparser_dealloc(self)
  722.     cdparserobject *self;
  723. {
  724.     int i;
  725.  
  726.     for (i = 0; i < NCALLBACKS; i++) {
  727.         Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
  728.         self->ob_cdcallbacks[i].ob_cdcallback = NULL;
  729.         Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
  730.         self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
  731.     }
  732.     CDdeleteparser(self->ob_cdparser);
  733.     PyObject_Del(self);
  734. }
  735.  
  736. static PyObject *
  737. cdparser_getattr(self, name)
  738.     cdparserobject *self;
  739.     char *name;
  740. {
  741.     if (self->ob_cdparser == NULL) {
  742.         PyErr_SetString(PyExc_RuntimeError, "no parser active");
  743.         return NULL;
  744.     }
  745.  
  746.     return Py_FindMethod(cdparser_methods, (PyObject *)self, name);
  747. }
  748.  
  749. PyTypeObject CdParsertype = {
  750.     PyObject_HEAD_INIT(&PyType_Type)
  751.     0,            /*ob_size*/
  752.     "cdparser",        /*tp_name*/
  753.     sizeof(cdparserobject),    /*tp_size*/
  754.     0,            /*tp_itemsize*/
  755.     /* methods */
  756.     (destructor)cdparser_dealloc, /*tp_dealloc*/
  757.     0,            /*tp_print*/
  758.     (getattrfunc)cdparser_getattr, /*tp_getattr*/
  759.     0,            /*tp_setattr*/
  760.     0,            /*tp_compare*/
  761.     0,            /*tp_repr*/
  762. };
  763.  
  764. static PyObject *
  765. newcdparserobject(cdp)
  766.     CDPARSER *cdp;
  767. {
  768.     cdparserobject *p;
  769.     int i;
  770.  
  771.     p = PyObject_New(cdparserobject, &CdParsertype);
  772.     if (p == NULL)
  773.         return NULL;
  774.     p->ob_cdparser = cdp;
  775.     for (i = 0; i < NCALLBACKS; i++) {
  776.         p->ob_cdcallbacks[i].ob_cdcallback = NULL;
  777.         p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
  778.     }
  779.     return (PyObject *) p;
  780. }
  781.  
  782. static PyObject *
  783. CD_createparser(self, args)
  784.     PyObject *self, *args;
  785. {
  786.     CDPARSER *cdp;
  787.  
  788.     if (!PyArg_ParseTuple(args, ":createparser"))
  789.         return NULL;
  790.     cdp = CDcreateparser();
  791.     if (cdp == NULL) {
  792.         PyErr_SetString(CdError, "createparser failed");
  793.         return NULL;
  794.     }
  795.  
  796.     return newcdparserobject(cdp);
  797. }
  798.  
  799. static PyObject *
  800. CD_msftoframe(self, args)
  801.     PyObject *self, *args;
  802. {
  803.     int min, sec, frame;
  804.  
  805.     if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame))
  806.         return NULL;
  807.  
  808.     return PyInt_FromLong((long) CDmsftoframe(min, sec, frame));
  809. }
  810.     
  811. static PyMethodDef CD_methods[] = {
  812.     {"open",        (PyCFunction)CD_open,        1},
  813.     {"createparser",    (PyCFunction)CD_createparser,    1},
  814.     {"msftoframe",        (PyCFunction)CD_msftoframe,    1},
  815.     {NULL,        NULL}    /* Sentinel */
  816. };
  817.  
  818. void
  819. initcd()
  820. {
  821.     PyObject *m, *d;
  822.  
  823.     m = Py_InitModule("cd", CD_methods);
  824.     d = PyModule_GetDict(m);
  825.  
  826.     CdError = PyErr_NewException("cd.error", NULL, NULL);
  827.     PyDict_SetItemString(d, "error", CdError);
  828.  
  829.     /* Identifiers for the different types of callbacks from the parser */
  830.     PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio));
  831.     PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum));
  832.     PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index));
  833.     PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime));
  834.     PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime));
  835.     PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog));
  836.     PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident));
  837.     PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control));
  838.  
  839.     /* Block size information for digital audio data */
  840.     PyDict_SetItemString(d, "DATASIZE",
  841.                PyInt_FromLong((long) CDDA_DATASIZE));
  842.     PyDict_SetItemString(d, "BLOCKSIZE",
  843.                PyInt_FromLong((long) CDDA_BLOCKSIZE));
  844.  
  845.     /* Possible states for the cd player */
  846.     PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR));
  847.     PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC));
  848.     PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY));
  849.     PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING));
  850.     PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED));
  851.     PyDict_SetItemString(d, "STILL", PyInt_FromLong((long) CD_STILL));
  852. #ifdef CD_CDROM            /* only newer versions of the library */
  853.     PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM));
  854. #endif
  855.  
  856.     if (PyErr_Occurred())
  857.         Py_FatalError("can't initialize module cd");
  858. }
  859.